// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


/**
 * @fileoverview Unit tests for bite.layer.soy.QuickConstruction.
 *
 * @author jasonstredwick@google.com (Jason Stredwick)
 */


goog.require('bite.common.test_framework.DomTests');
goog.require('bite.common.test_framework.SoyTests');
goog.require('bite.common.mvc.helper');
goog.require('bite.layer.QuickConstruction');
goog.require('bite.layer.soy.QuickConstruction');
goog.require('goog.dom');
goog.require('goog.dom.query');
goog.require('goog.events');
goog.require('goog.testing.PropertyReplacer');


var stubs_ = new goog.testing.PropertyReplacer();


function setUp() {
}


function tearDown() {
  stubs_.reset();
}


/**
 * Used to test dom element attributes.
 * @param {Array} input For inputs.
 * @param {Array} check For checks.
 * @param {Array} disable For disabled.
 */
function attributeTests(input, check, disable) {
  var tests = bite.common.test_framework.DomTests.getInstance();

  var expectedInputs = {};
  expectedInputs[bite.layer.QuickConstruction.Input_.CODE] = input[0];
  expectedInputs[bite.layer.QuickConstruction.Input_.CODE_CSS] = input[1];
  expectedInputs[bite.layer.QuickConstruction.Input_.CODE_JS_BG] = input[2];
  expectedInputs[bite.layer.QuickConstruction.Input_.CODE_JS_CS] = input[3];
  expectedInputs[bite.layer.QuickConstruction.Input_.NAME] = input[4];
  tests.testElementEqualsValue(expectedInputs, 'value');

  var expectedChecks = {};
  expectedChecks[bite.layer.QuickConstruction.Input_.ONDEMAND_NEVER] =
      check[0];
  expectedChecks[bite.layer.QuickConstruction.Input_.ONDEMAND_OFF] = check[1];
  expectedChecks[bite.layer.QuickConstruction.Input_.ONDEMAND_ON] = check[2];
  expectedChecks[bite.layer.QuickConstruction.Input_.STATE_ALWAYS] = check[3];
  expectedChecks[bite.layer.QuickConstruction.Input_.STATE_OFF] = check[4];
  expectedChecks[bite.layer.QuickConstruction.Input_.STATE_ON] = check[5];
  tests.testElementBooleanValue(expectedChecks, 'checked');

  var expectedDisabled = {};
  expectedDisabled[bite.layer.QuickConstruction.Input_.NAME] = disable[0];
  tests.testElementBooleanValue(expectedDisabled, 'disabled');
}


/**
 * Test behaviors.
 */
function testBehavior() {
  var qc = new bite.layer.QuickConstruction();
  assertTrue('Call to init', qc.init(''));
  assertTrue('IsInitialized', qc.isInitialized());

  assertTrue('IsDisabled, should be false', qc.isDisabled());
  qc.enable();
  assertFalse('IsDisabled, should be true', qc.isDisabled());

  assertFalse('IsVisibile, should be false', qc.isVisible());
  qc.show();
  assertTrue('IsVisibile - show, should be false', qc.isVisible());
  qc.hide();
  assertFalse('IsVisibile - hide, should be false', qc.isVisible());

  // Clean up
  qc.undoSetup_();
}


/**
 * Test the bite.layer.QuickConstruction
 *     Button presses for code selection and code saving during save button
 *     press.
 */
function testCode() {
  var qc = new bite.layer.QuickConstruction();
  assertTrue(qc.init(''));
  assertTrue(qc.isInitialized());

  var data = {};
  data[bite.layer.QuickConstruction.Data.BACKGROUND_JS] = 'backgroundJs';
  data[bite.layer.QuickConstruction.Data.CONTENT_CSS] = 'contentCss';
  data[bite.layer.QuickConstruction.Data.CONTENT_JS] = 'contentJs';
  data[bite.layer.QuickConstruction.Data.EDIT] = 'true';
  data[bite.layer.QuickConstruction.Data.NAME] = 'name';
  data[bite.layer.QuickConstruction.Data.ONDEMAND] = 'fixed';
  data[bite.layer.QuickConstruction.Data.STATE] = 'fixed';
  assertTrue(qc.update(data));

  /**
   * Test updating code text areas by "clicking the appropriate button".
   */
  // Find the code selection element to use for simulating its change.
  var query = goog.dom.query('[id="' +
      bite.layer.QuickConstruction.Input_.CODE_SELECT + '"]');
  assertEquals(1, query.length);

  // Set "entered" text in code window.
  qc.code_.value = 'code1';
  // Verify that background code is as initialized.
  assertEquals(qc.bgJsCode_.value, 'backgroundJs');
  // Set up the event.
  var event = {target: {selectedIndex: 1}};
  // "Change" code selection box to content javascript.
  qc.handleOnChangeCode_(event);
  // Verify that the background code has changed to current code.
  assertEquals(qc.bgJsCode_.value, 'code1');

  // Set "entered" text in code window.
  qc.code_.value = 'code2';
  // Verify that content code is as initialized.
  assertEquals(qc.csJsCode_.value, 'contentJs');
  // Set up the event.
  event = {target: {selectedIndex: 2}};
  // "Change" code selection box to css.
  qc.handleOnChangeCode_(event);
  // Verify that the content javascript code has changed to current code.
  assertEquals(qc.csJsCode_.value, 'code2');

  // Set "entered" text in code window.
  qc.code_.value = 'code3';
  // Verify that css code is as initialized.
  assertEquals(qc.cssCode_.value, 'contentCss');
  // Set up the event.
  event = {target: {selectedIndex: 0}};
  // "Change" code selection box to background javascript.
  qc.handleOnChangeCode_(event);
  // Verify that the css code has changed to current code.
  assertEquals(qc.cssCode_.value, 'code3');

  /**
   * Test that save updates the current selected code.
   */
  // Set "entered" text in code window.
  qc.code_.value = 'code4';
  // Verify that background code is the last updated value.
  assertEquals(qc.bgJsCode_.value, 'code1');
  // "Click" the save button.
  query = goog.dom.query('[id="' +
      bite.layer.QuickConstruction.Button_.SAVE + '"]');
  assertEquals(1, query.length);
  qc.handleOnSave_();
  // Verify that the background code has changed to current code.
  assertEquals(qc.bgJsCode_.value, 'code4');

  // Clean up
  qc.undoSetup_();
}


/**
 * Test events.
 */
function testEvents() {
  var qc = new bite.layer.QuickConstruction();
  qc.init('');
  assertTrue(qc.isInitialized());

  // Test that general code window is the same as the background script,
  // the script storage text areas are set, name is enabled and set, and
  // radio buttons are switched to fixed.
  var data = {};
  data[bite.layer.QuickConstruction.Data.BACKGROUND_JS] = 'backgroundJs';
  data[bite.layer.QuickConstruction.Data.CONTENT_CSS] = 'contentCss';
  data[bite.layer.QuickConstruction.Data.CONTENT_JS] = 'contentJs';
  data[bite.layer.QuickConstruction.Data.EDIT] = 'true';
  data[bite.layer.QuickConstruction.Data.NAME] = 'name';
  data[bite.layer.QuickConstruction.Data.ONDEMAND] = 'fixed';
  data[bite.layer.QuickConstruction.Data.STATE] = 'fixed';

  assertTrue(qc.update(data));

  var calls = 0;

  var inc = function() {
    ++calls;
  }

  var save = function(event) {
    assertEquals(data[bite.layer.QuickConstruction.Data.NAME],
                 event.getData()[bite.layer.QuickConstruction.Data.NAME]);
    ++calls;
  }

  goog.events.listenOnce(qc, bite.layer.QuickConstructionEventType.CLOSE,
                         inc);
  goog.events.listenOnce(qc, bite.layer.QuickConstructionEventType.RESET, inc);
  goog.events.listenOnce(qc, bite.layer.QuickConstructionEventType.SAVE, save);

  qc.handleOnClose_();
  qc.handleOnReset_();
  qc.handleOnSave_();

  assertEquals(3, calls);

  // Clean up
  qc.undoSetup_();
}


/**
 * Test bite.layer.soy.QuickConstruction.getView.
 */
function testGetView() {
  var tests = bite.common.test_framework.SoyTests.getInstance();
  var template = bite.layer.soy.QuickConstruction.getView;
  var tag = 'href';

  var expectedValue = 'styles/quick_construction.css';
  var url = '';
  tests.testAttributeValue(assertEquals, expectedValue, tag, template,
      {baseUrl: url});

  tests.testAttributeValue(assertEquals, expectedValue, tag, template, {});

  url = 'http://www.google.com/';
  expectedValue =
      'http://www.google.com/styles/quick_construction.css';
  tests.testAttributeValue(assertEquals, expectedValue, tag, template,
      {baseUrl: url});
}


/**
 * Test bite.layer.QuickConstruction.initView,
 *      bite.layer,QuickConstruction.init,
 *      bite.layer.QuickConstruction.isInitialized,
 *      bite.layer.QuickConstruction.undoSetup_.
 */
function testInits() {
  var qc = new bite.layer.QuickConstruction();

  // Test initView
  assertFalse(qc.isViewInitialized_);
  assertFalse(qc.isInitialized());
  var baseUrl = 'http://www.google.com/';
  qc.initView(baseUrl);
  assertTrue(qc.isViewInitialized_);
  assertFalse(qc.isInitialized());

  qc.initView(baseUrl); // Should do nothing
  assertTrue(qc.isViewInitialized_);
  assertFalse(qc.isInitialized());

  var elements = goog.dom.getElementsByTagNameAndClass(goog.dom.TagName.LINK);
  var count = 0;
  for (var i = 0, len = elements.length; i < len; ++i) {
    if (elements[i].href ==
        'http://www.google.com/styles/quick_construction.css') {
      ++count;
    }
  }
  assertEquals(1, count);

  // Test init but do not include initView
  qc = new bite.layer.QuickConstruction();
  assertFalse(qc.isModelInitialized_);
  assertFalse(qc.isInitialized());
  qc.init();
  assertTrue(qc.isModelInitialized_);
  assertFalse(qc.isInitialized());

  var elements = {};
  elements[bite.layer.QuickConstruction.CONSOLE_ID_] = null;
  elements[bite.layer.QuickConstruction.Input_.CODE_SELECT] = null;
  elements[bite.layer.QuickConstruction.Button_.CLOSE] = null;
  elements[bite.layer.QuickConstruction.Button_.RESET] = null;
  elements[bite.layer.QuickConstruction.Button_.SAVE] = null;
  elements[bite.layer.QuickConstruction.Input_.ONDEMAND_NEVER] = null;
  elements[bite.layer.QuickConstruction.Input_.ONDEMAND_OFF] = null;
  elements[bite.layer.QuickConstruction.Input_.ONDEMAND_ON] = null;
  elements[bite.layer.QuickConstruction.Input_.STATE_ALWAYS] = null;
  elements[bite.layer.QuickConstruction.Input_.STATE_OFF] = null;
  elements[bite.layer.QuickConstruction.Input_.STATE_ON] = null;
  elements[bite.layer.QuickConstruction.Input_.CODE] = null;
  elements[bite.layer.QuickConstruction.Input_.CODE_JS_BG] = null;
  elements[bite.layer.QuickConstruction.Input_.CODE_JS_CS] = null;
  elements[bite.layer.QuickConstruction.Input_.CODE_CSS] = null;
  elements[bite.layer.QuickConstruction.Input_.NAME] = null;
  assertTrue(bite.common.mvc.helper.bulkGetElementById(elements));

  qc.init();
  assertTrue(qc.isModelInitialized_);
  assertFalse(qc.isInitialized());
  // This will be false if there is more than one element with the same id.
  assertTrue(bite.common.mvc.helper.bulkGetElementById(elements));

  // Make sure that initView can be called properly from init.
  qc.init(baseUrl);
  assertTrue(qc.isModelInitialized_);
  // isInitialized should now be true as the model, view, and controller are
  // initialized.
  assertTrue(qc.isInitialized());

  // Clean up
  qc.undoSetup_();
  elements = {};
  elements[bite.layer.QuickConstruction.CONSOLE_ID_] = null;
  assertFalse(bite.common.mvc.helper.bulkGetElementById(elements));
}


/**
 * Test the bite.layer.QuickConstruction
 *     Radio Buttons.
 */
function testRadioButtons() {
  var qc = new bite.layer.QuickConstruction();
  assertTrue(qc.init(''));
  assertTrue(qc.isInitialized());

  var data = {};
  data[bite.layer.QuickConstruction.Data.BACKGROUND_JS] = 'backgroundJs';
  data[bite.layer.QuickConstruction.Data.CONTENT_CSS] = 'contentCss';
  data[bite.layer.QuickConstruction.Data.CONTENT_JS] = 'contentJs';
  data[bite.layer.QuickConstruction.Data.EDIT] = 'true';
  data[bite.layer.QuickConstruction.Data.NAME] = 'name';
  assertTrue(qc.update(data));

  // Test "clicking" radio buttons.
  assertEquals('default', qc.ondemand_);
  assertEquals('default', qc.state_);

  qc.handleSetOndemand_(bite.layer.QuickConstruction.Radio_.NEVER);
  assertEquals('fixed', qc.ondemand_);
  assertEquals('default', qc.state_);

  qc.handleSetOndemand_(bite.layer.QuickConstruction.Radio_.ON);
  assertEquals('on', qc.ondemand_);
  assertEquals('default', qc.state_);

  qc.handleSetOndemand_(bite.layer.QuickConstruction.Radio_.OFF);
  assertEquals('off', qc.ondemand_);
  assertEquals('default', qc.state_);

  qc.ondemand_ = 'default';

  qc.handleSetState_(bite.layer.QuickConstruction.Radio_.ALWAYS);
  assertEquals('default', qc.ondemand_);
  assertEquals('fixed', qc.state_);

  qc.handleSetState_(bite.layer.QuickConstruction.Radio_.ON);
  assertEquals('default', qc.ondemand_);
  assertEquals('on', qc.state_);

  qc.handleSetState_(bite.layer.QuickConstruction.Radio_.OFF);
  assertEquals('default', qc.ondemand_);
  assertEquals('off', qc.state_);

  qc.handleSetOndemand_(bite.layer.QuickConstruction.Radio_.OFF);
  assertEquals('off', qc.ondemand_);
  assertEquals('off', qc.state_);

  // Clean up
  qc.undoSetup_();
}


/**
 * Test bite.layer.QuickConstruction.prototype.reset and
 *      bite.layer.QuickConstruction.prototype.update.
 */
function testResetUpdate() {
  var qc = new bite.layer.QuickConstruction();
  qc.init('');
  assertTrue(qc.isInitialized());

  // Test that general code window is the same as the background script,
  // the script storage text areas are set, name is enabled and set, and
  // radio buttons are switched to fixed.
  var data = {};
  data[bite.layer.QuickConstruction.Data.BACKGROUND_JS] = 'backgroundJs';
  data[bite.layer.QuickConstruction.Data.CONTENT_CSS] = 'contentCss';
  data[bite.layer.QuickConstruction.Data.CONTENT_JS] = 'contentJs';
  data[bite.layer.QuickConstruction.Data.EDIT] = 'true';
  data[bite.layer.QuickConstruction.Data.NAME] = 'name';
  data[bite.layer.QuickConstruction.Data.ONDEMAND] = 'fixed';
  data[bite.layer.QuickConstruction.Data.STATE] = 'fixed';

  // Test update I
  attributeTests(['', '', '', '', ''],
                 [false, false, false, false, false, false],
                 [false]);
  assertTrue(qc.update(data));
  attributeTests(['backgroundJs', 'contentCss', 'backgroundJs', 'contentJs',
                  'name'],
                 [true, false, false, true, false, false],
                 [false]);

  // Test reset
  assertTrue(qc.reset());
  attributeTests(['', '', '', '', ''],
                 [false, false, false, false, false, false],
                 [false]);

  // Test update II
  delete data[bite.layer.QuickConstruction.Data.BACKGROUND_JS];
  data[bite.layer.QuickConstruction.Data.CONTENT_CSS] = 'contentCss';
  delete data[bite.layer.QuickConstruction.Data.CONTENT_JS];
  delete data[bite.layer.QuickConstruction.Data.EDIT];
  delete data[bite.layer.QuickConstruction.Data.NAME];
  data[bite.layer.QuickConstruction.Data.ONDEMAND] = 'off';
  data[bite.layer.QuickConstruction.Data.STATE] = 'off';
  assertTrue(qc.update(data));
  attributeTests(['', 'contentCss', '', '', ''],
                 [false, true, false, false, true, false],
                 [false]);

  // Test update III
  data[bite.layer.QuickConstruction.Data.BACKGROUND_JS] = 'backgroundJs';
  delete data[bite.layer.QuickConstruction.Data.CONTENT_CSS];
  data[bite.layer.QuickConstruction.Data.EDIT] = 'false';
  data[bite.layer.QuickConstruction.Data.ONDEMAND] = 'on';
  data[bite.layer.QuickConstruction.Data.STATE] = 'on';
  assertTrue(qc.update(data));
  attributeTests(['backgroundJs', 'contentCss', 'backgroundJs', '', ''],
                 [false, false, true, false, false, true],
                 [true]);

  // Clean up
  qc.undoSetup_();
}

